#include "virtual_pinctrl.h"


/* 引脚支持的复用功能列表 */
static const char * const pin_functions[] = {
	"gpio", "af0", "af1",
	"af2", "af3", "af4",
	"af5", "af6", "af7",
	"af8", "af9", "af10",
	"af11", "af12", "af13",
	"af14", "af15", "analog",
	"reserved",
};

/* 引脚列表 */
static const struct pinctrl_pin_desc pins_desc[] = {
	{0, "pin0", NULL},
	{1, "pin1", NULL},
	{2, "pin2", NULL},
	{3, "pin3", NULL},
	{4, "pin4", NULL},
	{5, "pin5", NULL},
};

/* 引脚组 */
const char *pin_groups[] = {pins_desc[0].name, pins_desc[1].name, pins_desc[2].name, pins_desc[3].name, pins_desc[4].name, pins_desc[5].name};

/* 缓存引脚配置 */
unsigned long pin_configs[ARRAY_SIZE(pins_desc)] = {0};
/* 缓存引脚复用功能配置 */
unsigned long pin_mux[ARRAY_SIZE(pins_desc)] = {0};

/* 获取总共多少组，将一个引脚作为一个组 */
static int virtual_get_groups_count(struct pinctrl_dev *pctldev)
{
	return ARRAY_SIZE(pins_desc);
}

/* 获取每某一组的名称，组名与引脚名相同 */
static const char *virtual_get_group_name(struct pinctrl_dev *pctldev, unsigned group)
{
	if (group >= ARRAY_SIZE(pins_desc))
		return NULL;

	return pins_desc[group].name;
}

/* 获取某一组的所有引脚 */
static int virtual_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, const unsigned **pins, unsigned *npins)
{
	if (group >= ARRAY_SIZE(pins_desc))
		return -EINVAL;

	*pins = &pins_desc[group].number;
	*npins = 1;

	return 0;
}

/* 解析设备树内容为pinctrl_map列表 */
static int virtual_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, unsigned *num_maps)
{
	int i;
	int num_groups;
	int num_functions;
	u32 config;
	char *buffer;
	const char *group;
	const char *function;
	unsigned long *configs;
	struct pinctrl_map *pctl_map;

	/* 获取引脚数 */
	for(num_groups=0; ; num_groups++)
	{
		if(of_property_read_string_index(np, "groups", num_groups, &group) < 0)
			break;
	}
	/* 获取功能数 */
	for(num_functions=0; ; num_functions++)
	{
		if(of_property_read_string_index(np, "functions", num_functions, &function) < 0)
			break;
	}
	/* 引脚数和功能数必须相等 */
	if((num_groups != num_functions) || (num_groups == 0))
	{
		printk("device tree error\r\n");
		return -EINVAL;
	}

	/* 分配pinctrl_map和配置字，每个（组）引脚2个pinctrl_map加4byte配置字，pinctrl_map位于前面部分空间 */
	buffer = kmalloc((sizeof(struct pinctrl_map) * num_groups * 2) + (num_groups * sizeof(unsigned long)), GFP_KERNEL);
	if(!buffer) {
		printk("alloc pinctrl_map failed\r\n");
		return -ENOMEM;
	}

	/* 偏移到pinctrl_map地址 */
	pctl_map = (struct pinctrl_map*)buffer;
	/* 偏移到配置字地址 */
	configs = (unsigned long*)(buffer + sizeof(struct pinctrl_map) * num_groups * 2);

	for(i=0; i<num_groups; i++)
	{
		of_property_read_string_index(np, "groups", i, &group);
		of_property_read_string_index(np, "functions", i, &function);
		if(of_property_read_u32_index(np, "configs", i, &config) == 0)
			configs[i] = config;
		else
			configs[i] = 0x9988;

		pctl_map[i*2].type = PIN_MAP_TYPE_MUX_GROUP;
		pctl_map[i*2].data.mux.function = function;
		pctl_map[i*2].data.mux.group = group;

		pctl_map[i*2+1].type = PIN_MAP_TYPE_CONFIGS_GROUP;
		pctl_map[i*2+1].data.configs.group_or_pin = group;
		pctl_map[i*2+1].data.configs.num_configs = 1;
		pctl_map[i*2+1].data.configs.configs = &configs[i];
	}

	*map = pctl_map;
	*num_maps = num_groups * 2;

	return 0;
}

/* 释放virtual_dt_node_to_map中分配的资源 */
static void virtual_dt_free_map(struct pinctrl_dev *pctldev, struct pinctrl_map *map, unsigned num_maps)
{
	kfree(map);
}

/* 获取引脚组的引脚和处理设备树操的作函数集合 */
static const struct pinctrl_ops virtual_ops = {
	.get_groups_count = virtual_get_groups_count,
	.get_group_name = virtual_get_group_name,
	.get_group_pins = virtual_get_group_pins,
	.dt_node_to_map = virtual_dt_node_to_map,
	.dt_free_map = virtual_dt_free_map,
};

/* 获取引脚配置 */
static int virtual_pconf_get(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *config)
{
	if(pin >= ARRAY_SIZE(pin_configs))
		return -EINVAL;

	*config = pin_configs[pin];

	return 0;
}

/* 配置引脚 */
static int virtual_pconf_set(struct pinctrl_dev *pctldev, unsigned pin, unsigned long *configs, unsigned num_configs)
{
	if((num_configs != 1) || (pin >= ARRAY_SIZE(pin_configs)))
		return -EINVAL;

	pin_configs[pin] = *configs;
	printk("pin config %s as 0x%lx\n", pctldev->desc->pins[pin].name, *configs);

	return 0;
}

/* 获取引脚组配置 */
static int virtual_pconf_group_get(struct pinctrl_dev *pctldev, unsigned group, unsigned long *config)
{
	if(group >= ARRAY_SIZE(pin_configs))
		return -EINVAL;

	*config = pin_configs[group];

	return 0;
}

/* 配置引脚组 */
static int virtual_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, unsigned long *configs, unsigned num_configs)
{
	if((num_configs != 1) || (group >= ARRAY_SIZE(pin_configs)))
		return -EINVAL;

	pin_configs[group] = *configs;
	printk("group config %s as 0x%lx\n", pctldev->desc->pins[group].name, *configs);

	return 0;
}

static void virtual_pconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin)
{
	if(pin >= ARRAY_SIZE(pin_configs))
		return ;

	seq_printf(s, "0x%lx", pin_configs[pin]);
}

static void virtual_pconf_group_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned group)
{
	if(group >= ARRAY_SIZE(pin_configs))
		return ;

	seq_printf(s, "0x%lx", pin_configs[group]);
}

/* 引脚配置的操作函数集合 */
static const struct pinconf_ops virtual_pconf_ops = {
	.pin_config_get = virtual_pconf_get,
	.pin_config_set = virtual_pconf_set,
	.pin_config_group_get = virtual_pconf_group_get,
	.pin_config_group_set = virtual_pconf_group_set,
	.pin_config_dbg_show = virtual_pconf_dbg_show,
	.pin_config_group_dbg_show = virtual_pconf_group_dbg_show,
};

/* 获取共计多少种复用功能 */
static int virtual_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
{
	return ARRAY_SIZE(pin_functions);
}

/* 获取某种复用功能的名称 */
static const char *virtual_pmx_get_func_name(struct pinctrl_dev *pctldev, unsigned function)
{
	if(function >= ARRAY_SIZE(pin_functions))
		return NULL;

	return pin_functions[function];
}

/* 获取支持某复用功能的引脚组 */
static int virtual_pmx_get_func_groups(struct pinctrl_dev *pctldev, unsigned function, const char * const **groups, unsigned * const num_groups)
{
	if(function >= ARRAY_SIZE(pin_functions))
		return -EINVAL;

	*groups = pin_groups;
	*num_groups = ARRAY_SIZE(pin_groups);

	return 0;
}

/* 设置引脚组的复用功能 */
static int virtual_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned function, unsigned group)
{
	if((group >= ARRAY_SIZE(pin_mux)) || (function >= ARRAY_SIZE(pin_functions)))
		return -EINVAL;

	pin_mux[group] = function;
	printk("group mux %s as 0x%x\n", pctldev->desc->pins[group].name, function);

	return 0;
}

/* 引脚复用功能选择和GPIO控制相关的操作函数集合 */
static const struct pinmux_ops virtual_pmx_ops = {
	.get_functions_count = virtual_pmx_get_funcs_cnt,
	.get_function_name = virtual_pmx_get_func_name,
	.get_function_groups = virtual_pmx_get_func_groups,
	.set_mux = virtual_pmx_set_mux,
	.strict = true,
};

//设备和驱动匹配成功执行
static int virtual_probe(struct platform_device *pdev)
{
	struct pinctrl_desc *pctl_desc;
	struct pinctrl_dev *pctl_dev;

	printk("%s\n", __FUNCTION__);

	/* a. 分配pinctrl_desc */
	pctl_desc = devm_kzalloc(&pdev->dev, sizeof(struct pinctrl_desc), GFP_KERNEL);
	if(!pctl_desc) {
		printk("alloc pctl_desc failed\r\n");
		return -ENOMEM;
	}

	/* b. 设置pinctrl_desc */
	/* b.1 设置名称和所属模块 */
	pctl_desc->name = dev_name(&pdev->dev);
	pctl_desc->owner = THIS_MODULE;
	/* b.2 描述单个引脚 */
	pctl_desc->pins = pins_desc;
	pctl_desc->npins = ARRAY_SIZE(pins_desc);
	/* b.3 绑定用于获取引脚组的引脚和处理设备树操的作函数集合 */
	pctl_desc->pctlops = &virtual_ops;
	/* b.5 绑定引脚配置的操作函数集合 */
	pctl_desc->confops = &virtual_pconf_ops;
	/* b.4 绑定引脚复用功能选择和GPIO控制相关的操作函数集合 */
	pctl_desc->pmxops = &virtual_pmx_ops;
	/* c. 注册pinctrl_desc */
	pctl_dev = devm_pinctrl_register(&pdev->dev, pctl_desc, NULL);
	if (IS_ERR(pctl_dev)) {
		printk("Failed pinctrl register\n");
		return PTR_ERR(pctl_dev);
	}

	return 0;
}

//设备或驱动卸载时执行
static int virtual_remove(struct platform_device *pdev)
{
	printk("%s\n", __FUNCTION__);
	return 0;
}

/* 匹配列表，用于设备树和平台驱动匹配 */
static const struct of_device_id virtual_of_match[] = {
	{.compatible = "atk,virtual_pinctrl"},
	{ /* Sentinel */ }
};
/* 平台驱动 */
static struct platform_driver virtual_drv = {
	.driver = {
		.name = "virtual_pinctrl",
		.owner = THIS_MODULE,
		.pm = NULL,
		.of_match_table = virtual_of_match,
	},
	.probe = virtual_probe,
	.remove = virtual_remove,
};
static int __init virtual_drv_init(void)
{
	int result;

	printk("%s\r\n", __FUNCTION__);

	//注册平台驱动
	result = platform_driver_register(&virtual_drv);
	if(result != 0)
		printk("add virtual driver failed\r\n");
	return result;
}

static void __exit virtual_drv_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	//注销平台驱动
	platform_driver_unregister(&virtual_drv);
}

module_init(virtual_drv_init);
module_exit(virtual_drv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("virtual_drv");
